/*
 * Designed and developed by 2017 skydoves (Jaewoong Eum)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.skydoves.colorpickerview.sliders;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
import android.widget.ImageView;
import androidx.annotation.ColorInt;
import androidx.annotation.ColorRes;
import androidx.annotation.DimenRes;
import androidx.annotation.DrawableRes;
import androidx.annotation.FloatRange;
import androidx.core.content.ContextCompat;
import androidx.core.content.res.ResourcesCompat;
import com.skydoves.colorpickerview.ActionMode;
import com.skydoves.colorpickerview.ColorPickerView;

/** AbstractSlider is the abstract class for implementing sliders. */
@SuppressWarnings("unused")
abstract class AbstractSlider extends FrameLayout {

  public ColorPickerView colorPickerView;
  protected Paint colorPaint;
  protected Paint borderPaint;
  protected float selectorPosition = 1.0f;
  protected int selectedX = 0;
  protected int selectedY = 0;
  protected float selectorPositionY = 1.0f;
  protected Drawable selectorDrawable;
  protected int borderSize = 2;
  protected int borderColor = Color.BLACK;
  protected boolean enableBorder = true;
  protected int color = Color.WHITE;
  protected ImageView selector;
  protected String preferenceName;
  protected float cornerRadius = 0f; // 圆角半径，默认为0（直角）
  protected boolean isSquareMode = false; // 是否为方形模式，默认为长条模式

  public AbstractSlider(Context context) {
    super(context);
    onCreate();
  }

  @Override
  public void setEnabled(boolean enabled) {
    super.setEnabled(enabled);
    selector.setVisibility(enabled ? VISIBLE : INVISIBLE);
    this.setClickable(enabled);
  }

  public AbstractSlider(Context context, AttributeSet attrs) {
    super(context, attrs);
    getAttrs(attrs);
    onCreate();
  }

  public AbstractSlider(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    getAttrs(attrs);
    onCreate();
  }

  @TargetApi(Build.VERSION_CODES.LOLLIPOP)
  public AbstractSlider(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);
    getAttrs(attrs);
    onCreate();
  }

  /** gets attribute sets style from layout */
  protected abstract void getAttrs(AttributeSet attrs);

  /** update paint color whenever the triggered colors are changed. */
  protected abstract void updatePaint(Paint colorPaint);

  /**
   * assembles about the selected color.
   *
   * @return assembled color.
   */
  public abstract @ColorInt int assembleColor();

  private void onCreate() {
    this.colorPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    this.borderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    this.borderPaint.setStyle(Paint.Style.STROKE);
    this.borderPaint.setStrokeWidth(borderSize);
    this.borderPaint.setColor(borderColor);
    this.setBackgroundColor(Color.WHITE);

    selector = new ImageView(getContext());
    if (selectorDrawable != null) {
      setSelectorDrawable(selectorDrawable);
    }

    initializeSelector();
  }

  @Override
  protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    float width = getWidth();
    float height = getMeasuredHeight();
    
    // 根据是否设置了圆角来决定绘制方式
    if (cornerRadius > 0) {
      // 绘制圆角矩形
      canvas.drawRoundRect(0, 0, width, height, cornerRadius, cornerRadius, colorPaint);
      // 绘制圆角边框（如果启用了边框）
      if (enableBorder && borderSize > 0) {
        // 调整边框的圆角大小，避免边框超出
        float borderRadius = cornerRadius - borderSize / 2f;
        if (borderRadius < 0) borderRadius = 0;
        canvas.drawRoundRect(0, 0, width, height, borderRadius, borderRadius, borderPaint);
      }
    } else {
      // 绘制普通矩形
      canvas.drawRect(0, 0, width, height, colorPaint);
      // 绘制边框（如果启用了边框）
      if (enableBorder) {
        canvas.drawRect(0, 0, width, height, borderPaint);
      }
    }
  }

  /** called by {@link ColorPickerView} whenever {@link ColorPickerView} is triggered. */
  public void notifyColor() {
    color = colorPickerView.getPureColor();
    updatePaint(colorPaint);
    invalidate();
  }

  @SuppressLint("ClickableViewAccessibility")
  @Override
  public boolean onTouchEvent(MotionEvent event) {
    if (!this.isEnabled()) {
      return false;
    }

    if (colorPickerView != null) {
      switch (event.getActionMasked()) {
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_DOWN:
        case MotionEvent.ACTION_MOVE:
          selector.setPressed(true);
          // 在方形模式下，需要检查x和y坐标是否都在范围内
          if (isSquareMode) {
            if (event.getX() > getWidth() || event.getX() < 0 || event.getY() > getHeight() || event.getY() < 0) {
              return false;
            }
          } else {
            // 长条模式下，只检查x坐标
            if (event.getX() > getWidth() || event.getX() < 0) {
              return false;
            }
          }
          onTouchReceived(event);
          return true;
        default:
          selector.setPressed(false);
          return false;
      }
    } else {
      return false;
    }
  }

  private void onTouchReceived(MotionEvent event) {
    // 计算可用区域（考虑滑块大小）
    int selectorWidth = selector.getWidth();
    int selectorHeight = selector.getHeight();
    int availableWidth = getWidth() - selectorWidth;
    int availableHeight = getHeight() - selectorHeight;
    
    // 计算事件位置相对于可用区域的比例
    float eventX = event.getX();
    // 确保x在有效范围内（0到getWidth()）
    eventX = Math.max(0, Math.min(eventX, getWidth()));
    
    // 计算滑块位置（使滑块中心对应触摸点）
    float x = eventX - selectorWidth / 2;
    // 确保滑块完全在控件内
    selectedX = (int) Math.max(0, Math.min(x, availableWidth));
    selector.setX(selectedX);
    
    // 计算位置比例 - 修复计算方式，确保值正确
    if (availableWidth > 0) {
      selectorPosition = (selectedX) / (float)availableWidth;
    } else {
      selectorPosition = 1.0f;
    }
    
    // 在方形模式下，还需要处理y坐标
    if (isSquareMode) {
      float eventY = event.getY();
      // 确保y在有效范围内（0到getHeight()）
      eventY = Math.max(0, Math.min(eventY, getHeight()));
      
      // 计算滑块位置（使滑块中心对应触摸点）
      float y = eventY - selectorHeight / 2;
      // 确保滑块完全在控件内
      selectedY = (int) Math.max(0, Math.min(y, availableHeight));
      selector.setY(selectedY);
      
      // 计算位置比例（反转，让顶部为1.0，底部为0.0）
      if (availableHeight > 0) {
        selectorPositionY = 1.0f - (selectedY / (float)availableHeight);
      } else {
        selectorPositionY = 1.0f;
      }
    } else {
      // 长条模式下，保持selector在垂直居中位置
      selector.setY((getHeight() - selectorHeight) / 2f);
    }
    
    // 触发颜色更新
    if (colorPickerView.getActionMode() == ColorPickerView.ActionMode.LAST) {
      if (event.getAction() == MotionEvent.ACTION_UP) {
        colorPickerView.fireColorListener(assembleColor(), true);
      }
    } else {
      colorPickerView.fireColorListener(assembleColor(), true);
    }

    // 只有当colorPickerView显示flagView且flagView不为null时才接收触摸事件
    if (colorPickerView != null && colorPickerView.getFlagView() != null && colorPickerView.isShowFlagView()) {
      colorPickerView.getFlagView().receiveOnTouchEvent(event);
    }
  }

  public void updateSelectorX(int x) {
    float left = selector.getWidth() / 2f;
    float right = getWidth() - left;
    // 确保x在有效范围内
    float boundedX = Math.max(left, Math.min(right, x));
    selectorPosition = (boundedX - left) / (right - left);
    selectedX = (int) getBoundaryX(boundedX);
    selector.setX(selectedX);
    
    // 长条模式下，保持selector在垂直居中位置
    if (!isSquareMode) {
      selector.setY((getHeight() - selector.getHeight()) / 2f);
    }
    
    colorPickerView.fireColorListener(assembleColor(), false);
  }
  
  /**
   * 更新选择器的Y坐标位置
   * @param y Y坐标值
   */
  public void updateSelectorY(int y) {
    float top = selector.getHeight() / 2f;
    float bottom = getHeight() - top;
    selectorPositionY = 1.0f - ((y - top) / (bottom - top)); // 反转y坐标
    if (selectorPositionY < 0) selectorPositionY = 0;
    if (selectorPositionY > 1.0f) selectorPositionY = 1.0f;
    selectedY = (int) getBoundaryY(y);
    selector.setY(selectedY);
    colorPickerView.fireColorListener(assembleColor(), false);
  }

  public void setSelectorPosition(@FloatRange(from = 0.0, to = 1.0) float selectorPosition) {
    this.selectorPosition = Math.max(0.0f, Math.min(selectorPosition, 1.0f));
    float availableWidth = getWidth() - selector.getWidth();
    if (availableWidth > 0) {
      float x = availableWidth * selectorPosition;
      selectedX = (int) x;
      selector.setX(selectedX);
    }
    
    // 长条模式下，保持selector在垂直居中位置
    if (!isSquareMode) {
      selector.setY((getHeight() - selector.getHeight()) / 2f);
    }
  }
  
  /**
   * 设置选择器的Y位置比例
   * @param selectorPositionY Y位置比例（0.0-1.0）
   */
  public void setSelectorPositionY(@FloatRange(from = 0.0, to = 1.0) float selectorPositionY) {
    this.selectorPositionY = Math.max(0.0f, Math.min(selectorPositionY, 1.0f));
    // 反转y坐标，让1.0对应顶部（亮），0.0对应底部（暗）
    float availableHeight = getHeight() - selector.getHeight();
    if (availableHeight > 0) {
      float y = availableHeight * (1.0f - selectorPositionY);
      selectedY = (int) y;
      selector.setY(selectedY);
    }
  }

  public void setSelectorByHalfSelectorPosition(
      @FloatRange(from = 0.0, to = 1.0) float selectorPosition) {
    this.selectorPosition = Math.max(0.0f, Math.min(selectorPosition, 1.0f));
    float availableWidth = getWidth() - selector.getWidth();
    if (availableWidth > 0) {
      float x = availableWidth * selectorPosition;
      selectedX = (int) x;
      selector.setX(selectedX);
    }
  }

  private float getBoundaryX(float x) {
    int selectorHalfWidth = selector.getWidth() / 2;
    int maxPos = getWidth() - selector.getWidth();
    // 计算滑块中心点的边界
    float centerX = x;
    if (centerX <= selectorHalfWidth) {
      return 0; // 滑块左边界对齐控件左边界
    } else if (centerX >= getWidth() - selectorHalfWidth) {
      return maxPos; // 滑块右边界对齐控件右边界
    }
    return centerX - selectorHalfWidth;
  }
  
  /**
   * 获取受边界限制的Y坐标
   * @param y 原始Y坐标
   * @return 受边界限制后的Y坐标
   */
  private float getBoundaryY(float y) {
    int selectorHalfHeight = selector.getHeight() / 2;
    int maxPos = getHeight() - selector.getHeight();
    // 计算滑块中心点的边界
    float centerY = y;
    if (centerY <= selectorHalfHeight) {
      return 0; // 滑块上边界对齐控件上边界
    } else if (centerY >= getHeight() - selectorHalfHeight) {
      return maxPos; // 滑块下边界对齐控件下边界
    }
    return centerY - selectorHalfHeight;
  }

  protected int getSelectorSize() {
    return (int) (selector.getWidth());
  }

  protected int getBorderHalfSize() {
    return (int) (borderSize * 0.5f);
  }

  private void initializeSelector() {
    getViewTreeObserver()
        .addOnGlobalLayoutListener(
            new ViewTreeObserver.OnGlobalLayoutListener() {
              @Override
              public void onGlobalLayout() {
                getViewTreeObserver().removeOnGlobalLayoutListener(this);
                onInflateFinished();
              }
            });
  }

  /**
   * sets a drawable of the selector.
   *
   * @param drawable drawable of the selector.
   */
  public void setSelectorDrawable(Drawable drawable) {
    removeView(selector);
    this.selectorDrawable = drawable;
    this.selector.setImageDrawable(drawable);
    FrameLayout.LayoutParams thumbParams =
        new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
    thumbParams.gravity = Gravity.CENTER;
    addView(selector, thumbParams);
  }

  /**
   * sets a drawable resource of the selector.
   *
   * @param resource a drawable resource of the selector.
   */
  public void setSelectorDrawableRes(@DrawableRes int resource) {
    Drawable drawable = ResourcesCompat.getDrawable(getContext().getResources(), resource, null);
    setSelectorDrawable(drawable);
  }

  /**
   * sets a color of the slider border.
   *
   * @param color color of the slider border.
   */
  public void setBorderColor(@ColorInt int color) {
    this.borderColor = color;
    this.borderPaint.setColor(color);
    invalidate();
  }

  /**
   * sets a color resource of the slider border.
   *
   * @param resource color resource of the slider border.
   */
  public void setBorderColorRes(@ColorRes int resource) {
    int color = ContextCompat.getColor(getContext(), resource);
    setBorderColor(color);
  }

  /**
   * sets a size of the slide border.
   *
   * @param borderSize ize of the slide border.
   */
  public void setBorderSize(int borderSize) {
    this.borderSize = borderSize;
    this.borderPaint.setStrokeWidth(borderSize);
    invalidate();
  }
  
  /**
   * 设置圆角半径
   * @param cornerRadius 圆角半径值（像素）
   */
  public void setCornerRadius(float cornerRadius) {
    this.cornerRadius = cornerRadius;
    invalidate();
  }
  
  /**
   * 设置是否启用边框
   * @param enableBorder 是否启用边框
   */
  public void setEnableBorder(boolean enableBorder) {
    this.enableBorder = enableBorder;
    invalidate();
  }
  
  /**
   * 获取是否启用了边框
   * @return 是否启用边框
   */
  public boolean isEnableBorder() {
    return enableBorder;
  }
  
  /**
   * 设置是否为方形模式
   * @param squareMode 是否为方形模式
   */
  public void setSquareMode(boolean squareMode) {
    this.isSquareMode = squareMode;
    // 如果切换到方形模式，需要更新选择器位置
    if (squareMode) {
      // 确保选择器在视图范围内
      int maxPosY = getHeight() - selector.getHeight();
      if (selectedY > maxPosY) {
        selectedY = maxPosY;
        selector.setY(selectedY);
      }
    } else {
      // 切换回长条模式，将选择器垂直居中
      selector.setY((getHeight() - selector.getHeight()) / 2f);
    }
    invalidate();
  }
  
  /**
   * 获取是否为方形模式
   * @return 是否为方形模式
   */
  public boolean isSquareMode() {
    return isSquareMode;
  }
  
  /**
   * 获取选择器Y位置比例
   * @return Y位置比例（0.0-1.0）
   */
  public float getSelectorPositionY() {
    return selectorPositionY;
  }
  
  /**
   * 获取当前圆角半径
   * @return 圆角半径值
   */
  public float getCornerRadius() {
    return cornerRadius;
  }

  /**
   * sets a size of the slide border using dimension resource.
   *
   * @param resource a size of the slide border.
   */
  public void setBorderSizeRes(@DimenRes int resource) {
    int borderSize = (int) getContext().getResources().getDimension(resource);
    setBorderSize(borderSize);
  }

  /** called when the inflating finished. */
  public abstract void onInflateFinished();

  /**
   * gets assembled color
   *
   * @return color
   */
  public int getColor() {
    return color;
  }

  /**
   * attaches {@link ColorPickerView} to slider.
   *
   * @param colorPickerView {@link ColorPickerView}.
   */
  public void attachColorPickerView(ColorPickerView colorPickerView) {
    this.colorPickerView = colorPickerView;
  }

  /**
   * gets selector's position ratio.
   *
   * @return selector's position ratio.
   */
  protected float getSelectorPosition() {
    return this.selectorPosition;
  }

  /**
   * gets selected x coordinate.
   *
   * @return selected x coordinate.
   */
  public int getSelectedX() {
    return this.selectedX;
  }

  /**
   * gets the preference name.
   *
   * @return preference name.
   */
  public String getPreferenceName() {
    return preferenceName;
  }

  /**
   * sets the preference name.
   *
   * @param preferenceName preference name.
   */
  public void setPreferenceName(String preferenceName) {
    this.preferenceName = preferenceName;
  }
}
